package com.wechat.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wechat.gateway.ratelimit.RateLimitConfig;
import com.wechat.gateway.ratelimit.RateLimitRuleManager;
import com.wechat.gateway.ratelimit.TokenBucketManager;
import com.wechat.gateway.ratelimit.TokenBucketResult;
import com.wechat.gateway.service.TokenService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 基于令牌桶的限流过滤器
 */
@Slf4j
@Component
public class RateLimitFilter extends AbstractGatewayFilterFactory<RateLimitFilter.Config> {

    @Autowired
    private RateLimitRuleManager ruleManager;

    @Autowired
    private TokenBucketManager bucketManager;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TokenService tokenService;

    public RateLimitFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            if (!config.enabled) {
                return chain.filter(exchange);
            }
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            String method = getHttpMethod(request);
            Optional<RateLimitConfig> ruleOpt = ruleManager.matchRule(path, method);
            if (ruleOpt.isEmpty()) {
                log.debug("路径 {} 无匹配的限流规则，直接通过", path);
                return chain.filter(exchange);
            }
            RateLimitConfig rule = ruleOpt.get();
            String ip = getClientIp(request, exchange);
            Long userId = tokenService.getUserId(request);
            String bucketKey = rule.generateBucketKey(ip, userId, path);

            return bucketManager.tryConsume(bucketKey, rule, rule.getTokensPerRequest())
                    .flatMap(result -> {
                        if (result.isAllowed()) {
                            // 添加限流相关响应头
                            addRateLimitHeaders(exchange.getResponse(), result, rule);
                            log.debug("请求通过限流检查: {} - 剩余令牌: {}", bucketKey, result.getRemainingTokens());
                            return chain.filter(exchange);
                        } else {
                            // 被限流，返回429状态码
                            log.warn("请求被限流: {} - 等待时间: {}秒", bucketKey, result.getWaitTime());
                            return rateLimitedResponse(exchange, result, rule);
                        }
                    });
        });
    }

    /**
     * 添加限流相关的响应头
     */
    private void addRateLimitHeaders(ServerHttpResponse response, TokenBucketResult result, RateLimitConfig rule) {
        HttpHeaders headers = response.getHeaders();
        headers.add("X-RateLimit-Limit", String.valueOf(rule.getCapacity()));
        headers.add("X-RateLimit-Remaining", String.valueOf(result.getRemainingTokens()));
        headers.add("X-RateLimit-Reset", String.valueOf(System.currentTimeMillis() / 1000 + 60));
        headers.add("X-RateLimit-Rule", rule.getRuleName());
        headers.add("X-RateLimit-Bucket", result.getBucketKey());
        headers.add("X-RateLimit-Retry-After", String.valueOf(result.getWaitTime()));
    }

    /**
     * 返回限流响应
     */
    private Mono<Void> rateLimitedResponse(
            org.springframework.web.server.ServerWebExchange exchange,
            TokenBucketResult result,
            RateLimitConfig rule) {

        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

        // 添加限流响应头
        addRateLimitHeaders(response, result, rule);
        response.getHeaders().add("Retry-After", String.valueOf(result.getWaitTime()));

        Map<String, Object> responseBody = new HashMap<>();
        responseBody.put("code", HttpStatus.TOO_MANY_REQUESTS.value());
        responseBody.put("message", "请求频率过高，请稍后重试");
        responseBody.put("rule", rule.getRuleName());
        responseBody.put("bucket", result.getBucketKey());
        responseBody.put("retryAfter", result.getWaitTime());
        responseBody.put("timestamp", System.currentTimeMillis());
        responseBody.put("path", exchange.getRequest().getURI().getPath());
        responseBody.put("method", getHttpMethod(exchange.getRequest()));

        try {
            String body = objectMapper.writeValueAsString(responseBody);
            DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
            return response.writeWith(Flux.just(buffer));
        } catch (JsonProcessingException e) {
            log.error("序列化限流响应失败", e);
            return response.setComplete();
        }
    }

    /**
     * 判断是否为内网IP
     */
    private boolean isInternalIp(String ip) {
        if (ip == null || ip.isEmpty()) {
            return false;
        }

        try {
            String[] parts = ip.split("\\.");
            if (parts.length != 4) {
                return false;
            }

            int first = Integer.parseInt(parts[0]);
            int second = Integer.parseInt(parts[1]);

            // 10.0.0.0/8
            if (first == 10) {
                return true;
            }

            // 172.16.0.0/12
            if (first == 172 && second >= 16 && second <= 31) {
                return true;
            }

            // 192.168.0.0/16
            if (first == 192 && second == 168) {
                return true;
            }

            // 127.0.0.0/8
            if (first == 127) {
                return true;
            }

            return false;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private String getHttpMethod(ServerHttpRequest request) {
        try {
            HttpMethod method = request.getMethod();
            return method.name();
        } catch (Exception e) {
            log.warn("无法获取 HTTP 请求方法 {}", e.getMessage());
            return "UNKNOWN";
        }
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(ServerHttpRequest request, ServerWebExchange exchange) {
        // 优先从X-Forwarded-For获取
        String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            // X-Forwarded-For可能包含多个IP，取第一个
            return xForwardedFor.split(",")[0].trim();
        }

        // 从X-Real-IP获取
        String xRealIp = request.getHeaders().getFirst("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        // 从Proxy-Client-IP获取
        String proxyClientIp = request.getHeaders().getFirst("Proxy-Client-IP");
        if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
            return proxyClientIp;
        }

        // 从WL-Proxy-Client-IP获取
        String wlProxyClientIp = request.getHeaders().getFirst("WL-Proxy-Client-IP");
        if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
            return wlProxyClientIp;
        }

        // 最后从远程地址获取
        if (exchange.getRequest().getRemoteAddress() != null) {
            return exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
        }
        return "unknown";
    }

    /**
     * 配置类
     */
    @Data
    public static class Config {
        private boolean enabled = true;
    }

    //    @Override
//    public GatewayFilter apply(Config config) {
//        return (exchange, chain) -> {
//            // 检查过滤器是否启用
//            if (!config.isEnabled()) {
//                return chain.filter(exchange);
//            }
//
//            ServerHttpRequest request = exchange.getRequest();
//            String path = request.getURI().getPath();
//            String method = request.getMethodValue();
//
//            // 匹配限流规则
//            Optional<RateLimitConfig> ruleOpt = ruleManager.matchRule(path, method);
//            if (ruleOpt.isEmpty()) {
//                log.debug("路径 {} 无匹配的限流规则，直接通过", path);
//                return chain.filter(exchange);
//            }
//
//            RateLimitConfig rule = ruleOpt.get();
//            log.debug("路径 {} 匹配到限流规则: {}", path, rule.getRuleName());
//
//            // 生成桶键
//            String ip = getClientIp(request);
//            String userId = request.getHeaders().getFirst("X-User-Id");
//            String bucketKey = rule.generateBucketKey(ip, userId, path);
//
//            // 尝试获取令牌
//            return bucketManager.tryConsume(bucketKey, rule, rule.getTokensPerRequest())
//                    .flatMap(result -> {
//                        if (result.isAllowed()) {
//                            // 添加限流相关响应头
//                            addRateLimitHeaders(exchange.getResponse(), result, rule);
//                            log.debug("请求通过限流检查: {} - 剩余令牌: {}", bucketKey, result.getRemainingTokens());
//                            return chain.filter(exchange);
//                        } else {
//                            // 被限流，返回429状态码
//                            log.warn("请求被限流: {} - 等待时间: {}秒", bucketKey, result.getWaitTime());
//                            return rateLimitedResponse(exchange, result, rule);
//                        }
//                    })
//                    .onErrorResume(throwable -> {
//                        // 发生错误时，记录日志并允许请求通过
//                        log.error("限流处理发生错误，允许请求通过: {}", throwable.getMessage(), throwable);
//                        return chain.filter(exchange);
//                    });
//        };
//    }
//
//    /**
//     * 添加限流相关的响应头
//     */
//    private void addRateLimitHeaders(ServerHttpResponse response, TokenBucketResult result, RateLimitConfig rule) {
//        HttpHeaders headers = response.getHeaders();
//        headers.add("X-RateLimit-Limit", String.valueOf(rule.getCapacity()));
//        headers.add("X-RateLimit-Remaining", String.valueOf(result.getRemainingTokens()));
//        headers.add("X-RateLimit-Reset", String.valueOf(System.currentTimeMillis() / 1000 + 60));
//        headers.add("X-RateLimit-Rule", rule.getRuleName());
//        headers.add("X-RateLimit-Bucket", result.getBucketKey());
//        headers.add("X-RateLimit-Retry-After", String.valueOf(result.getWaitTime()));
//    }
//
//    /**
//     * 返回限流响应
//     */
//    private Mono<Void> rateLimitedResponse(
//            org.springframework.web.server.ServerWebExchange exchange,
//            TokenBucketResult result,
//            RateLimitConfig rule) {
//
//        ServerHttpResponse response = exchange.getResponse();
//        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
//        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
//
//        // 添加限流响应头
//        addRateLimitHeaders(response, result, rule);
//        response.getHeaders().add("Retry-After", String.valueOf(result.getWaitTime()));
//
//        Map<String, Object> responseBody = new HashMap<>();
//        responseBody.put("code", HttpStatus.TOO_MANY_REQUESTS.value());
//        responseBody.put("message", "请求频率过高，请稍后重试");
//        responseBody.put("rule", rule.getRuleName());
//        responseBody.put("bucket", result.getBucketKey());
//        responseBody.put("retryAfter", result.getWaitTime());
//        responseBody.put("timestamp", System.currentTimeMillis());
//        responseBody.put("path", exchange.getRequest().getURI().getPath());
//
//        try {
//            String body = objectMapper.writeValueAsString(responseBody);
//            DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
//            return response.writeWith(Flux.just(buffer));
//        } catch (JsonProcessingException e) {
//            log.error("序列化限流响应失败", e);
//            return response.setComplete();
//        }
//    }
//
//    /**
//     * 获取客户端IP
//     */
//    private String getClientIp(ServerHttpRequest request) {
//        String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
//        String xRealIp = request.getHeaders().getFirst("X-Real-IP");
//
//        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
//            return xForwardedFor.split(",")[0].trim();
//        }
//
//        if (xRealIp != null && !xRealIp.isEmpty()) {
//            return xRealIp;
//        }
//
//        return request.getRemoteAddress() != null ?
//                request.getRemoteAddress().getAddress().getHostAddress() :
//                "unknown";
//    }
}